package cn.windfly.don.listener;

import java.io.File;
import java.lang.reflect.Field;
import java.net.URISyntaxException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;

//import com.mchange.v2.c3p0.ComboPooledDataSource;

import cn.windfly.don.Constant;
import cn.windfly.don.DonConfig;
import cn.windfly.util.LogUtil;

@WebListener
public class DependsOnNameListener implements ServletContextListener {

	public static String BasePath;
	File binBasePath;
	File jarBasePath = new File(
			DependsOnNameListener.class.getProtectionDomain().getCodeSource().getLocation().getFile()).getParentFile();

	@Override
	public void contextInitialized(ServletContextEvent servletContextEvent) {
		BasePath = servletContextEvent.getServletContext().getRealPath("/") + File.separator;
//		binBasePath = new File(BasePath + "WEB-INF/classes");
		try {
			binBasePath =new File(this.getClass().getClassLoader().getResource("/").toURI());
		} catch (URISyntaxException e1) {
			e1.printStackTrace();
		}
		LogUtil.info("don bin base path :",binBasePath );
		LogUtil.info( "don jar base path :", jarBasePath);
		Map<String, Object> injectClassMap;

		// 扫描类，在内存生成并注入属性
		try {
			injectClassMap = loadAndInjectClassToMapFromPath();
			// 加入到全局环境中
			servletContextEvent.getServletContext().setAttribute(Constant.INJECTCLASSMAP_SERVLET_CONTEXT,
					injectClassMap);
			// 加入初始始常量
			putContantToApplication(servletContextEvent.getServletContext());

			// 注入JDBC属性
			// * 取数据源,如果数据源为null,则认从don.properties文件中取配置信息 jdbc.driver<br>
			// * jdbc.url<br>
			// * jdbc.username<br>
			// * jdbc.password<br>
			// String jdbcUrl = DonConfig.getString("jdbc.url");
			// if (jdbcUrl != null) {
			// try {
			// ComboPooledDataSource combopooleddatasource = new
			// ComboPooledDataSource();
			// combopooleddatasource.setUser(DonConfig.getString("jdbc.username").trim());
			// combopooleddatasource.setPassword(DonConfig.getString("jdbc.password").trim());
			// combopooleddatasource.setJdbcUrl(DonConfig.getString("jdbc.url").trim());
			// combopooleddatasource.setDriverClass(DonConfig.getString("jdbc.driver").trim());
			// combopooleddatasource.setInitialPoolSize(2);
			// combopooleddatasource.setMinPoolSize(1);
			// combopooleddatasource.setMaxPoolSize(20);
			// combopooleddatasource.setMaxStatements(50);
			// combopooleddatasource.setMaxIdleTime(60);
			// JdbcUtil.setDataSource(combopooleddatasource);
			// } catch (PropertyVetoException e) {
			// e.printStackTrace();
			// }
			// }
		} catch (IllegalAccessException e) {
			LogUtil.error(e);
		}

	}

	/**
	 * 在全局环境中加入常量
	 *
	 * @param servletContext
	 */
	private void putContantToApplication(ServletContext servletContext) {
		String path = servletContext.getContextPath();
		path = path.equals("/") ? "" : path;
		servletContext.setAttribute("CONTEXT_PATH", path); // 供JSP页面中资源引用路径调用
		Properties property = DonConfig.getProperty();
		Iterator<Object> iterator = property.keySet().iterator();
		while (iterator.hasNext()) {
			String name = (String) iterator.next();
			if (name.startsWith("context_")) {
				servletContext.setAttribute(name, property.get(name));
			}

		}
	}

	@Override
	public void contextDestroyed(ServletContextEvent servletContextEvent) {
		// ignore
	}

	/**
	 * 加载以特殊后缀名结尾的类，并将类中特殊后缀名的属性进行注入
	 *
	 * @param binBasePath
	 * @return
	 */
	private Map<String, Object> loadAndInjectClassToMapFromPath() throws IllegalAccessException {
		HashMap<String, Object> map = new HashMap<String, Object>();

		loadInjectClass(binBasePath, map);
		loadInjectJar(jarBasePath, map);

		injectClass(map);
		return map;
	}

	/**
	 * 加载与 core-DON.jar同路径以下的所有jar包,只处理以DON.jar结尾的jar包
	 *
	 * @param jarBasePath
	 * @param map
	 */
	private void loadInjectJar(File jarBasePath, HashMap<String, Object> map) {
		if (jarBasePath.isDirectory()) {
			File[] files = jarBasePath.listFiles();
			for (File file : files) {
				loadInjectJar(file, map);
			}
		} else {
			if (jarBasePath.getName().endsWith("DON.jar")) {
				try {
					JarFile jarFile = new JarFile(jarBasePath);
					Enumeration<JarEntry> entries = jarFile.entries();
					while (entries.hasMoreElements()) {
						JarEntry jarEntry = entries.nextElement();
						String name = jarEntry.getName().replaceAll("/", ".");

						if (name.endsWith(".class")) {
							name = name.replace(".class", "");
							// 只处理特殊后缀名文件
							if (name.endsWith("Controller")) {// ||
																// name.endsWith("Service")
																// ||
																// name.endsWith("ServiceImpl")
																// ||
																// name.endsWith("Dao")
																// ||
																// name.endsWith("DaoImpl"))
																// {
								dealControllerFile(map, name);
							}
						}

					}
					jarFile.close();
				} catch (Exception e) {
					LogUtil.error(e);
				}
			}
		}
	}

	/**
	 * 将map中的类属性进行注入
	 * <p>
	 * *Controller 以*Controller注入<br/>
	 * *Service 以*ServiceImpl注入<br/>
	 * *Dao 以*DaoImpl注入
	 * </p>
	 *
	 * @param map
	 */
	private void injectClass(Map<String, Object> map) throws IllegalAccessException {
		for (Map.Entry<String, Object> entry : map.entrySet()) {
			Object obj = entry.getValue();
			for (Field field : obj.getClass().getDeclaredFields()) {
				field.setAccessible(true);

				String fieldName = field.getName();
				if (fieldName.endsWith("Controller")) {
					if (map.containsKey(field.getName())) {
						field.set(obj, map.get(field.getName()));
					}
					// } else if
					// (fieldName.endsWith("Service")||fieldName.endsWith("Dao")){
					// if (map.containsKey(field.getName()+"Impl")){
					// field.set(obj,map.get(field.getName()+"Impl"));
					// }
				}
			}
		}

	}

	/**
	 * 加载特殊后缀名类
	 * <p>
	 * *Controller,*Service,*ServiceImpl,*Dao,*DaoImpl
	 * </p>
	 */
	private void loadInjectClass(File path, Map<String, Object> map) {
		for (File file : path.listFiles()) {
			if (file.isDirectory()) { // 文件夹则递归
				loadInjectClass(file, map);
			} else {

				if (file.getName().endsWith(".class")) { // 只分析 class文件
					String filename = file.getPath().replace(binBasePath.getPath() + File.separator, "")
							.replace(".class", "").replace(File.separator, ".");
					// 只处理特殊后缀名文件
					if (filename.endsWith("Controller")) {// ||
															// filename.endsWith("Service")
															// ||
															// filename.endsWith("ServiceImpl")
															// ||
															// filename.endsWith("Dao")
															// ||
															// filename.endsWith("DaoImpl"))
															// {
						dealControllerFile(map, filename);
					}
				}

			}
		}
	}

	private void dealControllerFile(Map<String, Object> map, String filename) {
		try {
			Class<?> c = Class.forName(filename);
			// 只处理普通 class 类
			if (c.isInterface() || c.isAnnotation() || c.isArray() || c.isEnum()) {
				return;
			}
			// 映射文件名和实例。
			LogUtil.info( "\u81ea\u52a8\u52a0\u8f7d\u6620\u5c04:", c.getSimpleName());
			if (map.containsKey(c.getSimpleName())) {
				throw new RuntimeException(
						"Controller前缀名重复," + map.get(c.getSimpleName()).getClass().getName() + " " + c.getName());
			}
			// map.put(c.getName(), c.newInstance());
			map.put(c.getSimpleName(), c.newInstance());
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

}
